package com.xscha.tableforge.service.impl;

import com.xscha.tableforge.constants.DateFormatConstants;
import com.xscha.tableforge.constants.FieldType;
import com.xscha.tableforge.constants.SelectOptionConstants;
import com.xscha.tableforge.model.dto.FieldMetaDto;
import com.xscha.tableforge.model.dto.RelationMetaDto;
import com.xscha.tableforge.model.entity.FieldMeta;
import com.xscha.tableforge.model.entity.TableMeta;
import com.xscha.tableforge.model.vo.PageReq;
import com.xscha.tableforge.model.vo.PageResult;
import com.xscha.tableforge.repository.FieldMetaRepository;
import com.xscha.tableforge.repository.TableMetaRepository;
import com.xscha.tableforge.service.BaseService;
import com.xscha.tableforge.service.FieldMetaService;
import com.xscha.tableforge.service.RelationMetaService;
import com.xscha.tableforge.utils.EntityFieldUtil;
import com.xscha.tableforge.utils.IdUtil;
import com.xscha.soyue.common.core.utils.BeanMapperUtils;
import com.xscha.soyue.common.core.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 字段元数据服务实现类
 */
@Service
@Slf4j
public class FieldMetaServiceImpl extends BaseService<FieldMeta> implements FieldMetaService {

    private final FieldMetaRepository fieldMetaRepository;
    private final TableMetaRepository tableMetaRepository;
    private final DSLContext dslContext;
    private final RelationMetaService relationMetaService; // 添加依赖

    @Autowired
    public FieldMetaServiceImpl(FieldMetaRepository fieldMetaRepository, 
                               TableMetaRepository tableMetaRepository, 
                               DSLContext dslContext,
                               @Lazy RelationMetaService relationMetaService) { // 添加@Lazy注解
        this.fieldMetaRepository = fieldMetaRepository;
        this.tableMetaRepository = tableMetaRepository;
        this.dslContext = dslContext;
        this.relationMetaService = relationMetaService; // 注入依赖
    }

    @Override
    public FieldMeta findById(String id) {
        return fieldMetaRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("字段不存在"));
    }

    @Override
    public List<FieldMeta> findAllByTableId(String tableId) {
        return fieldMetaRepository.findAllByTableId(tableId);
    }

    @Override
    public PageResult<FieldMeta> findPageByTableId(String tableId, PageReq pageRequest) {
		PageReq processedReq = processPageRequest(pageRequest);
        return fieldMetaRepository.findPageByTableId(tableId, processedReq);
    }

    /**
     * 将FieldMeta转换为FieldMetaDto
     */
    private FieldMetaDto convertToFieldMetaDto(FieldMeta fieldMeta) {
        FieldMetaDto dto = new FieldMetaDto();
		BeanMapperUtils.map(fieldMeta, dto);
        dto.setOptions(EntityFieldUtil.convertJsonToOptions(fieldMeta.getOptions()));
        dto.setLookupOptions(fieldMeta.getLookupOptions());
        return dto;
    }

	/**
	 * 添加列到物理表
	 */
	private void addColumnToTable(String tableName, FieldMetaDto fieldMetaDto) {
		// 获取数据类型 - 使用父类BaseService中的方法
		DataType<?> dataType = EntityFieldUtil.getJooqDataType(fieldMetaDto.getDbFieldType());
		// 构建字段名
		String columnName = fieldMetaDto.getDbFieldName();
		// 构建SQL语句
		String typeName = dataType.getTypeName();
		String sql = "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + " " + typeName;
		// 添加NOT NULL约束
		if (fieldMetaDto.getNotNull() != null && fieldMetaDto.getNotNull()) {
			sql += " NOT NULL";
		}
		log.info("执行SQL: {}", sql);
		dslContext.execute(sql);
	}

    @Override
    @Transactional
    public List<FieldMeta> batchCreateFieldMetas(List<FieldMetaDto> fieldMetaDtos, String tableId, String userId) {
        List<FieldMeta> result = new ArrayList<>();
        
        for (FieldMetaDto dto : fieldMetaDtos) {
            FieldMeta fieldMeta = new FieldMeta();
			BeanMapperUtils.map(dto, fieldMeta);
            fieldMeta.setId(IdUtil.createDstId());
			fieldMeta.setOptions(EntityFieldUtil.processFieldOptions(dto));
            fieldMeta.setLookupOptions(dto.getLookupOptions());
            fieldMeta.setTableId(tableId);
            fieldMeta.setVersion(1);
            fieldMeta.setCreatedTime(LocalDateTime.now());
            fieldMeta.setCreatedBy(userId);
            fieldMeta.setDisplayOrder(dto.getDisplayOrder());
            
            fieldMetaRepository.save(fieldMeta);
            result.add(fieldMeta);
        }
        
        return result;
    }

    @Override
    @Transactional
    public FieldMeta updateFieldMeta(String id, FieldMetaDto fieldMetaDto, String userId) {
        FieldMeta fieldMeta = fieldMetaRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("字段不存在"));
        
        fieldMeta.setName(fieldMetaDto.getName());
        fieldMeta.setDescription(fieldMetaDto.getDescription());
		fieldMeta.setOptions(EntityFieldUtil.processFieldOptions(fieldMetaDto));
        fieldMeta.setType(fieldMetaDto.getType());
        fieldMeta.setCellValueType(fieldMetaDto.getCellValueType());
        fieldMeta.setIsMultipleCellValue(fieldMetaDto.getIsMultipleCellValue());
        fieldMeta.setNotNull(fieldMetaDto.getNotNull());
        fieldMeta.setIsUnique(fieldMetaDto.getIsUnique());
        fieldMeta.setIsComputed(fieldMetaDto.getIsComputed());
        fieldMeta.setIsLookup(fieldMetaDto.getIsLookup());
        fieldMeta.setIsPending(fieldMetaDto.getIsPending());
        fieldMeta.setHasError(fieldMetaDto.getHasError());
        fieldMeta.setLookupLinkedFieldId(fieldMetaDto.getLookupLinkedFieldId());
        fieldMeta.setLookupOptions(fieldMetaDto.getLookupOptions());
        fieldMeta.setDisplayOrder(fieldMetaDto.getDisplayOrder());
        fieldMeta.setVersion(fieldMeta.getVersion() + 1);
        fieldMeta.setLastModifiedTime(LocalDateTime.now());
        fieldMeta.setLastModifiedBy(userId);
        
        return fieldMetaRepository.save(fieldMeta);
    }

    @Override
    @Transactional
    public void deleteFieldMeta(String id, String userId) {
        FieldMeta fieldMeta = fieldMetaRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("字段不存在"));
        
        fieldMeta.setDeletedTime(LocalDateTime.now());
        fieldMeta.setLastModifiedTime(LocalDateTime.now());
        fieldMeta.setLastModifiedBy(userId);
        
        fieldMetaRepository.save(fieldMeta);
    }

	@Override
	protected Class<FieldMeta> getEntityClass() {
		return FieldMeta.class;
	}

	/**
     * 创建关联字段
     *
     * @param fieldMetaDto 字段元数据DTO
     * @param userId 创建者用户ID
     * @return 创建成功的字段元数据
     */
    @Transactional
    public FieldMeta createRelationField(FieldMetaDto fieldMetaDto, String userId) {
        // 1. 获取表元数据
        String tableId = fieldMetaDto.getTableId();
        TableMeta tableMeta = tableMetaRepository.findById(tableId)
                .orElseThrow(() -> new RuntimeException("表不存在"));
        
        // 2. 创建字段元数据对象
        FieldMeta fieldMeta = new FieldMeta();
		BeanMapperUtils.map(fieldMetaDto, fieldMeta);
        fieldMeta.setId(IdUtil.createFieldId());
		fieldMeta.setVersion(0);
        fieldMeta.setOptions(EntityFieldUtil.processFieldOptions(fieldMetaDto));
        fieldMeta.setLookupOptions(fieldMetaDto.getLookupOptions());
        fieldMeta.setCreatedTime(LocalDateTime.now());
        fieldMeta.setCreatedBy(userId);

        // 3. 设置dbFieldType
        if (fieldMeta.getDbFieldType() == null && fieldMeta.getType() != null) {
            fieldMeta.setDbFieldType(EntityFieldUtil.mapTypeToDbFieldType(fieldMeta.getType()));
        }
    
        // 4. 设置cellValueType默认值
        if (fieldMeta.getCellValueType() == null) {
            fieldMeta.setCellValueType(EntityFieldUtil.mapTypeToDbFieldType(fieldMeta.getType()));
        }
        
        // 5. 添加字段到物理表
        try {
            addColumnToTable(tableMeta.getDbTableName(), convertToFieldMetaDto(fieldMeta));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("添加字段到物理表失败", e);
        }
        
        // 6. 保存字段元数据
        fieldMetaRepository.save(fieldMeta);
        
        // 2. 从options中提取关联字段信息
        Map<String, Object> options = fieldMetaDto.getOptions();
        if (options == null || !options.containsKey("targetTableId") || 
            !options.containsKey("targetFieldId") || !options.containsKey("displayFieldId")) {
            throw new RuntimeException("关联字段配置不完整");
        }
        
        String targetTableId = options.get("targetTableId").toString();
        String targetFieldId = options.get("targetFieldId").toString();
        String displayFieldId = options.get("displayFieldId").toString();
        Boolean cascadeDelete = options.containsKey("cascadeDelete") ? 
                (Boolean) options.get("cascadeDelete") : false;
        
        // 3. 创建关联字段元数据
        RelationMetaDto relationMetaDto = new RelationMetaDto();
        relationMetaDto.setFieldId(fieldMeta.getId());
        relationMetaDto.setTargetTableId(targetTableId);
        relationMetaDto.setTargetFieldId(targetFieldId);
        relationMetaDto.setDisplayFieldId(displayFieldId);
        relationMetaDto.setRelationType(fieldMeta.getType());
        relationMetaDto.setCascadeDelete(cascadeDelete);
        
        relationMetaService.createRelationMeta(relationMetaDto, userId);
        
        return fieldMeta;
    }
    
    @Override
    @Transactional
    public FieldMeta createFieldMeta(FieldMetaDto fieldMetaDto, String userId) {
        // 检查是否为关联字段类型
        String type = fieldMetaDto.getType();
        FieldType fieldType = FieldType.fromCode(type);

        if (fieldType != null && fieldType.isRelation()) {
            return createRelationField(fieldMetaDto, userId);
        }

        // 原有的字段创建逻辑
        // 1. 获取表元数据
        String tableId = fieldMetaDto.getTableId();
        TableMeta tableMeta = tableMetaRepository.findById(tableId)
                .orElseThrow(() -> new RuntimeException("表不存在"));
        
        // 2. 创建字段元数据对象
        FieldMeta fieldMeta = new FieldMeta();
		BeanMapperUtils.map(fieldMetaDto, fieldMeta);
        fieldMeta.setId(IdUtil.createFieldId());
        fieldMeta.setOptions(EntityFieldUtil.processFieldOptions(fieldMetaDto));
        fieldMeta.setLookupOptions(fieldMetaDto.getLookupOptions());
        fieldMeta.setCreatedTime(LocalDateTime.now());
        fieldMeta.setCreatedBy(userId);

        // 3. 设置dbFieldType
        if (fieldMeta.getDbFieldType() == null && fieldMeta.getType() != null) {
            fieldMeta.setDbFieldType(EntityFieldUtil.mapTypeToDbFieldType(fieldMeta.getType()));
        }
    
        // 4. 设置cellValueType默认值
        if (fieldMeta.getCellValueType() == null) {
            fieldMeta.setCellValueType(EntityFieldUtil.mapTypeToDbFieldType(fieldMeta.getType()));
        }
        
        // 5. 添加字段到物理表
        try {
            addColumnToTable(tableMeta.getDbTableName(), convertToFieldMetaDto(fieldMeta));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("添加字段到物理表失败", e);
        }
        
        // 6. 保存字段元数据
        return fieldMetaRepository.save(fieldMeta);
    }
}